package controllers;

import java.sql.Timestamp;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import javax.persistence.Query;

import models.BadgeEntity;
import models.BadgeType;
import models.Comment;
import models.Handshake;
import models.Rating;
import models.Service;
import models.ServiceHasParticipants;
import models.Handshake.Status;
import models.HandshakeComment;
import models.Offer;
import models.Request;
import models.User;
import play.db.jpa.JPA;
import play.mvc.With;
import service.NotificationManager;

// Require Login
@With(Secure.class)
public class Handshakes extends BaseController
{
	/**
	 * Adds a user to the given offer.
	 * 
	 * @param id	id of the offer to which the user
	 * 				will be added.
	 * @throws Exception 
	 */
    public static void bindToOffer(Long id) throws Exception
    {
        User user = getConnectedUser();
    	Offer service = Offer.findById(id);
    	service.addUser(user);
    	
    	//Add Notification
    	User offerOwnerUser = service.owner;
    	String link = "offers/showdetails?id=" + id;
    	new NotificationManager().AddNewNotification(offerOwnerUser, user.fullname + " has applied to your offer.", link);
    	Offers.showDetails(service.id);
//    	renderTemplate("Handshakes/bind.html", (Service) service, true);
    }

    public static void cancelApplication(Long serviceId) {
    	Service service = Service.findById(serviceId);
    	( service).revokeUser(getConnectedUser());
    	showServiceDetails(serviceId);
    	renderTemplate("Handshakes/bind.html", true);
    }

    /**
	 * Adds a user to the given request.
	 * 
	 * @param id	id of the request to which the user
	 * 				will be added.
     * @throws Exception 
	 */
    public static void bindToRequest(Long id) throws Exception {
    	User user = getConnectedUser();
    	Request service = Request.findById(id);
    	service.addUser(user);

    	//Add Notification
    	User requestOwnerUser = service.owner;
    	String link = "requests/showdetails?id=" + id;
    	new NotificationManager().AddNewNotification(requestOwnerUser, user.fullname + " has applied to your request.", link);
    	Requests.showDetails(service.id);
    	//renderTemplate("Handshakes/bind.html", (Service) service, true);
    }

    public static void show(Long id) {
	User currentUser = getConnectedUser();
	Handshake handshake = Handshake.findById(id);
	List<Comment> comments = Comment.find("handshake = ?", handshake).fetch();
	Boolean originallyOffer = handshake.isOriginallyAnOffer;
	Integer commentCount = comments.size();

	User offerer = User.findById(handshake.offererId);
	User requester = User.findById(handshake.requesterId);
	Boolean handshakeParticipant = ((currentUser == offerer) || (currentUser == requester));
	
	render(currentUser, handshake, comments, originallyOffer, commentCount);
    }

    public static void list() {
        User user = getConnectedUser();
        List<Service> handshakes = Collections.emptyList();

		Query ownedQuery = JPA.em().createQuery("from " + Service.class.getName() + " where owner_Id=" + user.id + " and status <> 0 ");
		List<Object[]> ownedList = ownedQuery.getResultList();
		handshakes = new ArrayList(ownedList);
		//List<Service> ownedServices = new ArrayList(ownedList);
        //handshakes.addAll(ownedServices);
        
		Query participatedQuery = JPA.em().createQuery("from " + ServiceHasParticipants.class.getName() + " where user_Id=" + user.id);
		List<Object[]> participatedList = participatedQuery.getResultList();
		List<ServiceHasParticipants> participatedServices = new ArrayList(participatedList);
        
		for (ServiceHasParticipants participatedService: participatedServices)
		{
			Service pService = participatedService.service;
			if(pService.status != Service.Status.CREATED)
			{
				handshakes.add(pService);
			}
		}
		
        render(handshakes);
    }
 
    public static void search(String phrase) {
        User user = getConnectedUser();

        List<Handshake> allHandshakes = Handshake.findAll();

        render(user, allHandshakes, phrase);
    }

    public static void accept(Long serviceId, Long userId) {
    	Service service = Service.findById(serviceId);
    	User user = User.findById(userId);
    	service.approveUser(user);
    	service.setStatusByNumberOfParticipants();
    	showServiceDetails(serviceId);
    	
    	//renderTemplate("Handshakes/bind.html", service, true);
    }
    
    public static void ignore(Long serviceId, Long userId) {
    	Service service = Service.findById(serviceId);
    	User user = User.findById(userId);
		service.rejectUser(user);
		service.setStatusByNumberOfParticipants();
		showServiceDetails(serviceId);
		//renderTemplate("Handshakes/bind.html", service);
    }
    
    public static void start(Long handshakeId) {
        Handshake handshakeItem = Handshake.findById(handshakeId);

	Boolean startedByBoth, startedByOne;
	
	User user = getConnectedUser();
	if (user.id == handshakeItem.offererId) {
	    handshakeItem.offererStart = true;
	} else if (user.id == handshakeItem.requesterId) {
	    handshakeItem.requesterStart = true;
	}
        handshakeItem.save();

	startedByOne = (handshakeItem.offererStart || handshakeItem.requesterStart);
	startedByBoth = (handshakeItem.offererStart && handshakeItem.requesterStart);
	
	if (startedByBoth) {
	    User offerer = User.findById(handshakeItem.offererId);
	    User requester = User.findById(handshakeItem.requesterId);
	    
	    //offerer.balance += handshakeItem.offer.creditOffer;
	    //requester.balance -= handshakeItem.offer.creditRequest;
	    offerer.save();
	    requester.save();
	    handshakeItem.status = Status.STARTED;
	    handshakeItem.save();
	}

        renderTemplate("Handshakes/bind.html", handshakeItem, startedByBoth, startedByOne);
    }
    
    public static void cancel(Long handshakeId) {
        Handshake handshake = Handshake.findById(handshakeId);
        handshake.status = Status.CANCELLED;
        handshake.save();
        show(handshakeId);
    }
    
    public static void end(Long handshakeId) {
    	
        Handshake handshake = Handshake.findById(handshakeId);
        handshake.status = Status.DONE;
        handshake.save();
        updateBadgeForHandshake(handshake);
        
        show(handshakeId);
    }

    public static void saveComment(Long handshakeId)
    {
        User user = getConnectedUser();
        
        // create a new handshake comment.
        HandshakeComment comment = new HandshakeComment();
        comment.user = user;
        comment.handshake = Handshake.findById(handshakeId);
        comment.date = new Date();
        comment.text = request.params.get("message");
        comment.save();
        show(handshakeId);
    }

    
    private static void updateBadgeForHandshake(Handshake handshake){
    	updateBadgeForUser(handshake.offer.owner);
    	updateBadgeForUser(handshake.request.owner);
    }

    private static void updateBadgeForUser(User user){
    	Date now = new Date();
    	Timestamp sixMonthAgo = new Timestamp(now.getTime() - 86400000*30*6);

    	long count=Handshake.count("(offer.user.id = ? or request.user.id = ?) and creationDate> ?", user.id, user.id,sixMonthAgo);
    	user.badge=BadgeType.NEW_BEE;
//    	if(count>=5)
//    		user.badge=BadgeType.BUSY_BEE;
//    	if(count>=30)
//    		user.badge=BadgeType.WORKING_BEE;
//    	if(count>=60)
//    		user.badge=BadgeType.BUMBLE_BEE;
    	
       user.badge=BadgeType.NEW_BEE;
    	   
    
       
//    BadgeTable badgetable=new BadgeTable();
//    user = getConnectedUser();
//    Query getemailQuery = JPA.em().createQuery("select email from   " + User.class.getName() + " where id is " +user.id);
//    String email = (String) getemailQuery. getSingleResult();
//    badgetable.setEmail(email);
//    badgetable.setNewbie("NEW_BEE");
//    badgetable.save();
//    	
    	if(count>=5)
    		user.badge=BadgeType.Fivester;
    	if(count>=30)
    		user.badge=BadgeType.Populist;
    	if(count>=60)
    		user.badge=BadgeType.Guru;
    	user.save();
    	
    }
    
    //03.06.2012 Seyfi : For rating test can be removed after
    public static void rating() {
		render();
    }
    
    public static void feedback(Long id)
    {
    	Service serviceItem = Service.findById(id);
    	User user = getConnectedUser();
    	User serviceOwner = serviceItem.owner;
    	Boolean isOwner = (user == serviceOwner);
		AbstractMap<User, Rating> userApplications = new HashMap();
		Query acceptedParticipant = JPA.em().createQuery("from " + ServiceHasParticipants.class.getName() + " where service_Id=" + serviceItem.id + " and status = 1 ");
		List<Object[]> applicationStatus = acceptedParticipant.getResultList();
		List<ServiceHasParticipants> acceptedParticipants = new ArrayList(applicationStatus);
		for (ServiceHasParticipants serviceParticipant: acceptedParticipants)
		{
			// If rating exists, select rating; else create new rating
			User candidateUser = serviceParticipant.user;
			Rating r = setGetRate(candidateUser,serviceItem);
			userApplications.put(candidateUser, r);	
		}
		Rating ratingOwner = setGetRate(serviceOwner,serviceItem);
		ratingOwner.save();
		Boolean hasOccured = (serviceItem.status == Service.Status.COMPLETED);
    	render(serviceItem,userApplications,user,isOwner,serviceOwner, ratingOwner,hasOccured);
    }
    
    public static Rating setGetRate(User u, Service s)
    {
		Rating ratingItem = new Rating();
    	Query hasRatedBefore = JPA.em().createQuery("from " + Rating.class.getName() + " where service_Id=" + s.id + " and user_Id =" +u.id);
		List<Object[]> hasRatedList = hasRatedBefore.getResultList();
		List<Rating> hasRated = new ArrayList(hasRatedList);
		
		Boolean hasBeenRated = false;
		//get only first result, there should be no other
		for (Rating r : hasRated)
		{
			hasBeenRated = true;
			ratingItem = r;
			break;
		}
		if (!hasBeenRated)
		{
			ratingItem = new Rating();
			ratingItem.user = u;
			ratingItem.service = s;
			ratingItem.rating = 0;
			ratingItem.save();
		}
		return ratingItem;
    }
    		
    //public static void submitFeedback(Service serviceItem, AbstractMap<User,Rating> userApplications, Rating ratingOwner, Boolean hasOccured, Boolean isOwner){
    public static void submitFeedback(Long id,AbstractMap<User,Rating> userApplications,Rating ratingOwner,Boolean hasOccured){
    	User user = getConnectedUser();
    	Service serviceItem = Service.findById(id);
    	Boolean isOwner = (user == serviceItem.owner);
    	if(serviceItem.status != Service.Status.TRADED)
    	{
	    	if(hasOccured)
	    	{
	    		User serviceOwner = serviceItem.owner;
	    		serviceOwner.balance += serviceItem.getCredits().offererSocialPoint;
	    		serviceOwner.save();
	    		
	    		Query acceptedParticipant = JPA.em().createQuery("from " + ServiceHasParticipants.class.getName() + " where service_Id=" + serviceItem.id + " and status = 1 ");
	    		List<Object[]> applicationStatus = acceptedParticipant.getResultList();
	    		List<ServiceHasParticipants> acceptedParticipants = new ArrayList(applicationStatus);
	    		for (ServiceHasParticipants serviceParticipant: acceptedParticipants)
	    		{
	    			// If rating exists, select rating; else create new rating
	    			User candidateUser = serviceParticipant.user;
	    			candidateUser.balance -= serviceItem.getCredits().requesterSocialPoint;
	    			candidateUser.save();
	    		}
	    		serviceItem.status = Service.Status.TRADED;
	    	}
	    	else
	    	{
	    		serviceItem.status = Service.Status.CANCELLED;
	    	}
	    	serviceItem.save();
    	}
    	Users.profile(user.id);

    }
    
    public static void setRating(Long ratingId, int userRating)
    {
    	Rating ratingItem = Rating.findById(ratingId);
    	ratingItem.rating = userRating;
    	ratingItem.save();
    	updateUserRating(ratingId);
    }
    
    public static void updateUserRating(Long ratingId)
    {
    	Rating ratingItem = Rating.findById(ratingId);
    	User ratingUser = ratingItem.user;
    	double avgRating = 0.0;
    	Query hasRatedBefore = JPA.em().createQuery("select avg(rating) from " + Rating.class.getName() + " where user_Id =" + ratingUser.id + " and rating <> 0 " );
		avgRating = (Double)hasRatedBefore.getSingleResult();
		ratingUser.userRating = avgRating;
		ratingUser.save();
    
    }
    public static void setServiceCompleted(Long id)
    {
    	Service serviceItem = Service.findById(id);
    	serviceItem.status = Service.Status.COMPLETED;
    	serviceItem.save();
    	showServiceDetails(id);
    }
    
    public static void setServiceCancelled(Long id)
    {
    	Service serviceItem = Service.findById(id);
    	serviceItem.status = Service.Status.CANCELLED;
    	serviceItem.save();
    	showServiceDetails(id);
    }
    public static void setServiceReopen(Long id)
    {
    	Service serviceItem = Service.findById(id);
    	serviceItem.setStatusByNumberOfParticipants();
    	showServiceDetails(id);
    }
    public static void showServiceDetails(Long id)
    {
    	Service serviceItem = Service.findById(id);
    	if (serviceItem.getClass() == models.Offer.class)
    	{
    		Offers.showDetails(id);
    	}
    	if (serviceItem.getClass() == models.Request.class)
    	{
    		Requests.showDetails(id);
    	}
    }
    
}
